/**
 * @file asdu_parser.h
 * @brief ASDU解析器头文件
 * @details 本文件定义了104协议的ASDU解析器接口，包括通用ASDU解析、遥信数据ASDU
 *          解析、遥测数据ASDU解析、控制命令ASDU解析、系统命令ASDU解析等核心功能。
 *          支持多种数据类型的信息对象解析，确保解析的ASDU数据符合104协议规范。
 * 
 * @author zyb
 * @date 2025-10-07
 * @version 1.0
 * 
 * @note ASDU解析时需要验证数据完整性，防止解析错误的数据
 * @warning 解析后的ASDU数据需要调用相应的释放函数
 * 
 * @see asdu_parser.c
 * @see protocol_types.h
 * @see constants.h
 * @see error_codes.h
 */

#ifndef ASDU_PARSER_H
#define ASDU_PARSER_H

#include "protocol_types.h"

#ifdef __cplusplus
extern "C" {
#endif

/* ==================== 通用ASDU解析函数 ==================== */

/**
 * @brief 解析ASDU头部
 * @details 从字节流中解析ASDU头部信息，包括类型标识、可变结构限定词、
 *          传送原因、公共地址等字段。函数会验证头部格式和缓冲区大小。
 * 
 * @param buffer 输入缓冲区，不能为NULL
 * @param buffer_size 缓冲区大小，必须至少为ASDU_HEADER_SIZE
 * @param asdu ASDU结构输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 解析成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 缓冲区太小
 *         - PROTOCOL_ERROR_ASDU_INVALID: ASDU无效
 * 
 * @note 解析后的ASDU结构包含头部信息
 * @warning 缓冲区必须包含完整的ASDU头部数据
 * 
 * @see asdu_t
 * @see ASDU_HEADER_SIZE
 */
protocol_error_t parse_asdu_header(const uint8_t* buffer, size_t buffer_size, asdu_t* asdu);

/**
 * @brief 解析ASDU
 * @details 从字节流中解析完整的ASDU数据，包括头部和信息对象数据。
 *          函数会验证ASDU格式，然后解析信息对象数据部分。
 * 
 * @param buffer 输入缓冲区，不能为NULL
 * @param buffer_size 缓冲区大小
 * @param asdu ASDU结构输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 解析成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 缓冲区太小
 *         - PROTOCOL_ERROR_ASDU_INVALID: ASDU无效
 * 
 * @note 解析后的ASDU数据需要调用相应的释放函数
 * @warning 缓冲区必须包含完整的ASDU数据
 * 
 * @see asdu_t
 * @see parse_asdu_header
 */
protocol_error_t parse_asdu(const uint8_t* buffer, size_t buffer_size, asdu_t* asdu);

/* ==================== 遥信数据ASDU解析函数 ==================== */

/**
 * @brief 解析单点信息ASDU
 * @details 从ASDU中解析单点信息数据，包括M_SP_NA_1、M_SP_TA_1、M_SP_TB_1等类型。
 *          函数会根据ASDU类型解析相应的信息对象数据。
 * 
 * @param asdu ASDU结构指针，不能为NULL
 * @param info_objects 单点信息对象数组输出，不能为NULL
 * @param count 信息对象数量输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 解析成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_ASDU_INVALID: ASDU无效
 *         - PROTOCOL_ERROR_INVALID_PARAM: 无效参数
 * 
 * @note 解析后的信息对象数据需要调用相应的释放函数
 * @warning ASDU类型必须是单点信息类型
 * 
 * @see single_point_info_t
 * @see asdu_t
 */
protocol_error_t parse_single_point_asdu(const asdu_t* asdu, single_point_info_t* info_objects, uint8_t* count);

/**
 * @brief 解析双点信息ASDU
 * @details 从ASDU中解析双点信息数据，包括M_DP_NA_1、M_DP_TA_1、M_DP_TB_1等类型。
 *          函数会根据ASDU类型解析相应的信息对象数据。
 * 
 * @param asdu ASDU结构指针，不能为NULL
 * @param info_objects 双点信息对象数组输出，不能为NULL
 * @param count 信息对象数量输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 解析成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_ASDU_INVALID: ASDU无效
 *         - PROTOCOL_ERROR_INVALID_PARAM: 无效参数
 * 
 * @note 解析后的信息对象数据需要调用相应的释放函数
 * @warning ASDU类型必须是双点信息类型
 * 
 * @see double_point_info_t
 * @see asdu_t
 */
protocol_error_t parse_double_point_asdu(const asdu_t* asdu, double_point_info_t* info_objects, uint8_t* count);

/* ==================== 遥测数据ASDU解析函数 ==================== */

/**
 * @brief 解析测量值ASDU
 * @details 从ASDU中解析测量值数据，包括M_ME_NA_1、M_ME_NB_1、M_ME_NC_1等类型。
 *          函数会根据ASDU类型解析相应的信息对象数据。
 * 
 * @param asdu ASDU结构指针，不能为NULL
 * @param info_objects 测量值对象数组输出，不能为NULL
 * @param count 信息对象数量输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 解析成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_ASDU_INVALID: ASDU无效
 *         - PROTOCOL_ERROR_INVALID_PARAM: 无效参数
 * 
 * @note 解析后的信息对象数据需要调用相应的释放函数
 * @warning ASDU类型必须是测量值类型
 * 
 * @see measurement_info_t
 * @see asdu_t
 */
protocol_error_t parse_measurement_asdu(const asdu_t* asdu, measurement_info_t* info_objects, uint8_t* count);

/* ==================== 控制命令ASDU解析函数 ==================== */

/**
 * @brief 解析单点命令ASDU
 * @details 从ASDU中解析单点命令数据，包括C_SC_NA_1、C_SC_TA_1等类型。
 *          函数会根据ASDU类型解析相应的信息对象数据。
 * 
 * @param asdu ASDU结构指针，不能为NULL
 * @param info_objects 单点命令对象数组输出，不能为NULL
 * @param count 信息对象数量输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 解析成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_ASDU_INVALID: ASDU无效
 *         - PROTOCOL_ERROR_INVALID_PARAM: 无效参数
 * 
 * @note 解析后的信息对象数据需要调用相应的释放函数
 * @warning ASDU类型必须是单点命令类型
 * 
 * @see single_command_info_t
 * @see asdu_t
 */
protocol_error_t parse_single_command_asdu(const asdu_t* asdu, single_command_info_t* info_objects, uint8_t* count);

/**
 * @brief 解析双点命令ASDU
 * @details 从ASDU中解析双点命令数据，包括C_DC_NA_1、C_DC_TA_1等类型。
 *          函数会根据ASDU类型解析相应的信息对象数据。
 * 
 * @param asdu ASDU结构指针，不能为NULL
 * @param info_objects 双点命令对象数组输出，不能为NULL
 * @param count 信息对象数量输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 解析成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_ASDU_INVALID: ASDU无效
 *         - PROTOCOL_ERROR_INVALID_PARAM: 无效参数
 * 
 * @note 解析后的信息对象数据需要调用相应的释放函数
 * @warning ASDU类型必须是双点命令类型
 * 
 * @see double_command_info_t
 * @see asdu_t
 */
protocol_error_t parse_double_command_asdu(const asdu_t* asdu, double_command_info_t* info_objects, uint8_t* count);

/* ==================== 系统命令ASDU解析函数 ==================== */

/**
 * @brief 解析总召唤命令ASDU
 * @details 从ASDU中解析总召唤命令数据 (C_IC_NA_1)，提取召唤限定词。
 *          函数会验证ASDU类型，然后解析召唤限定词。
 * 
 * @param asdu ASDU结构指针，不能为NULL
 * @param qoi 召唤限定词输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 解析成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_ASDU_INVALID: ASDU无效
 *         - PROTOCOL_ERROR_INVALID_PARAM: 无效参数
 * 
 * @note 总召唤命令用于请求所有数据
 * @warning ASDU类型必须是C_IC_NA_1
 * 
 * @see qoi_t
 * @see asdu_t
 */
protocol_error_t parse_total_interrogation_asdu(const asdu_t* asdu, qoi_t* qoi);

/**
 * @brief 解析时钟同步命令ASDU
 * @details 从ASDU中解析时钟同步命令数据 (C_CS_NA_1)，提取时间戳。
 *          函数会验证ASDU类型，然后解析时间戳数据。
 * 
 * @param asdu ASDU结构指针，不能为NULL
 * @param timestamp 时间戳输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 解析成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_ASDU_INVALID: ASDU无效
 *         - PROTOCOL_ERROR_INVALID_PARAM: 无效参数
 * 
 * @note 时钟同步命令用于时间同步
 * @warning ASDU类型必须是C_CS_NA_1
 * 
 * @see cp56time2a_t
 * @see asdu_t
 */
protocol_error_t parse_clock_sync_asdu(const asdu_t* asdu, cp56time2a_t* timestamp);

/* ==================== 遥测值计算函数声明 ==================== */

/**
 * @brief 计算遥测值
 * @param raw_value 原始值 (0-32767)
 * @param full_scale 满量程值
 * @return 计算后的显示值
 */
float calculate_measured_value(uint16_t raw_value, float full_scale);

/**
 * @brief 解析遥测值
 * @param buffer 输入缓冲区
 * @param buffer_size 缓冲区大小
 * @param offset 偏移量
 * @param full_scale 满量程值
 * @param result 输出结果
 * @return 协议错误码
 */
protocol_error_t parse_measured_value(const uint8_t* buffer, size_t buffer_size, size_t offset, 
                                     float full_scale, float* result);

/* ==================== ASDU验证函数 ==================== */

/**
 * @brief 验证ASDU类型
 * @details 验证ASDU的类型标识是否有效。函数会检查类型标识是否在有效范围内，
 *          并验证类型标识是否符合104协议规范。
 * 
 * @param asdu ASDU结构指针，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 验证成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_ASDU_INVALID_TYPE: 无效ASDU类型
 * 
 * @note 验证包括类型标识范围检查
 * @warning 类型标识必须在有效范围内
 * 
 * @see asdu_t
 * @see type_id_t
 */
protocol_error_t validate_asdu_type(const asdu_t* asdu);

/**
 * @brief 验证ASDU数据
 * @details 验证ASDU的数据完整性，包括长度、格式等。
 *          函数会检查ASDU的基本结构和数据一致性。
 * 
 * @param asdu ASDU结构指针，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 验证成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_ASDU_INVALID: ASDU无效
 * 
 * @note 验证包括长度和格式检查
 * @warning ASDU数据必须完整有效
 * 
 * @see asdu_t
 */
protocol_error_t validate_asdu_data(const asdu_t* asdu);

/* ==================== ASDU辅助函数 ==================== */

/**
 * @brief 获取ASDU类型描述
 * @details 根据ASDU的类型标识获取对应的类型描述字符串。
 *          函数会返回类型标识的中文描述，便于调试和日志记录。
 * 
 * @param asdu ASDU结构指针，不能为NULL
 * @param description 描述字符串输出缓冲区，不能为NULL
 * @param description_size 缓冲区大小
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 获取成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 缓冲区太小
 * 
 * @note 描述字符串用于调试和日志记录
 * @warning 缓冲区必须足够大以容纳描述字符串
 * 
 * @see asdu_t
 * @see type_id_t
 */
protocol_error_t get_asdu_type_description(const asdu_t* asdu, char* description, size_t description_size);

/**
 * @brief 获取ASDU传送原因描述
 * @details 根据ASDU的传送原因获取对应的原因描述字符串。
 *          函数会返回传送原因的中文描述，便于调试和日志记录。
 * 
 * @param asdu ASDU结构指针，不能为NULL
 * @param description 描述字符串输出缓冲区，不能为NULL
 * @param description_size 缓冲区大小
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 获取成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 缓冲区太小
 * 
 * @note 描述字符串用于调试和日志记录
 * @warning 缓冲区必须足够大以容纳描述字符串
 * 
 * @see asdu_t
 * @see cause_of_transmission_t
 */
protocol_error_t get_asdu_cause_description(const asdu_t* asdu, char* description, size_t description_size);

#ifdef __cplusplus
}
#endif

#endif /* ASDU_PARSER_H */
